/*Splay 平衡树
* 1.rotate(x) 将编号为x的点转到父节点的位置

* 2.splay(x,k) 将编号为x的点转到编号为k的点下面
    x会每次走两步，直到走到k下面
    为维护平衡树的效率
    每次splay时会把经过的路径反过来

* 3.用懒标记记录某点及其子树的翻转状态
    x的懒标记代表以x为根的子树对应的区间
    当翻转区间[l,r]时，将l-1转到根，r+1转到根的右儿子
                l-1
        [1~l-2]       r+1
                  [l~r] [r+2~n]
    改变r+1的左儿子的懒标记即可

* 4.启发式合并
    每次优先将小的集合合并到大的集合，时间复杂度可以达到 O(nlogn)
    
    建立 n 棵 splay 树，合并时用并查集维护信息，
    当要合并两棵 splay 树时，直接暴力将一棵 splay 树插入到另外一棵 splay 树上，
    可采用启发式合并：
        即将更小的 splay 树合并到更大的 splay 树上。

    当合并时，将节点一个一个插入 splay 树中时，
    完全可以利用该节点的状态编号而不必生成新的节点编号，
    另外 splay 树中的状态节点编号与中序遍历表示的值的编号是相等的，
    且所有操作没有改变其对应的关系，所以可以直接利用状态节点编号返回查询的信息

* 本题:
    对于每一次的操作首先将要操作的一段的左右端点算出来，
    把左端点转到根节点的位置，右端点转到根节点的下方，
    那么右端点的左儿子的子树就代表要操作的序列
    l
         r
      op
*/

#define DEBUG
#pragma GCC optimize("O1,O2,O3,Ofast")
#pragma GCC optimize("no-stack-protector,unroll-loops,fast-math,inline")
#pragma GCC target("avx,avx2,fma")
#pragma GCC target("sse,sse2,sse3,sse4,sse4.1,sse4.2,ssse3")

#include <iostream>
#include <cstring>
using namespace std;

const int N = 5e5+10, INF = 0x3f3f3f3f;
int n, m;
struct node{
    int s[2], pa, val; //左右节点id 父节点id 当前点权值
    int size; //以当前节点为根的子树中节点的总数
    bool rev, same; //懒标记，反转，是否和根节点相同
    int ms, ls, rs, sum; //最大子段和，最大前缀和 最大后缀和 区间和
    void init(int _val,int _pa){ //初始化 权值 父节点
        s[0]=s[1]=0;
        val=_val, pa=_pa;
        size=1;
        rev=same=false;
        sum=ms=_val; //最大子段和至少包含一个数
        ls=rs=max(0, _val); //最大前缀，后缀可以不取数
    }
}tree[N];
int root;
int nodes[N], tt; //垃圾回收站，实现splay的空间回收
int w[N];

inline void pushup(int u)//向上更新信息
{  
    auto &U=tree[u], &L=tree[U.s[0]],  &R=tree[U.s[1]];
    U.size=L.size+R.size+1;
    U.sum=L.sum+R.sum+U.val;
    U.ls=max(L.ls, L.sum+R.ls+U.val);
    U.rs=max(R.rs, R.sum+L.rs+U.val);
    U.ms=max(max(L.ms, R.ms), L.rs+R.ls+U.val);
}

inline void pushdown(int u)//下放懒标记
{    
    auto &U=tree[u], &L=tree[U.s[0]],  &R=tree[U.s[1]];
    if(U.same) //处理相同标记
    {
        U.same=U.rev=0;
        if(U.s[0]) L.same=1, L.val=U.val, L.sum=L.val*L.size;
        if(U.s[1]) R.same=1, R.val=U.val, R.sum=R.val*R.size;
        if(U.val>0)
        {
            if(U.s[0]) L.ms=L.ls=L.rs=L.sum;
            if(U.s[1]) R.ms=R.ls=R.rs=R.sum;
        }
        else
        {
            if(U.s[0]) L.ms=L.val, L.ls=L.rs=0;
            if(U.s[1]) R.ms=R.val, R.ls=R.rs=0;
        }
    }
    else if(U.rev) //处理反转标记
    {
        U.rev=0;
        L.rev^=1, R.rev^=1;
        swap(L.rs, L.ls); swap(R.rs, R.ls);
        swap(L.s[0], L.s[1]); swap(R.s[0], R.s[1]);
    }
}

inline void rotate(int x)  //旋转 x上移一层
{
    int y=tree[x].pa, z=tree[y].pa; //父节点 祖父节点
    bool k=tree[y].s[1]==x; //x是否是父节点的子节点
    //交换x，y
    tree[z].s[tree[z].s[1]==y]=x; 
    tree[x].pa=z; 

    //将x的孩子节点接到y上
    tree[y].s[k]=tree[x].s[k^1], tree[tree[x].s[k^1]].pa=y;

    tree[x].s[k^1]=y, tree[y].pa=x;
    pushup(y), pushup(x);
}

inline void splay(int x,int k)//将x转到k下面
{ 
    while(tree[x].pa != k)
    {
        int y=tree[x].pa, z=tree[y].pa;
        if(z!=k)
        {
            if((tree[y].s[1]==x)^(tree[z].s[1]==y)) //不在一条直线上
                rotate(x);
            else
                rotate(y);
        }
        //此时x，x的父节点，x的祖父节点一定在一条直线上
        rotate(x);
    }
    if(!k) //x为根节点
        root=x;
}

inline int get_k(int k)    //查询中序遍历中排名为k的点
{
    int u=root;
    while(u)
    {
        pushdown(u);
        if(tree[tree[u].s[0]].size>=k) //在左侧
            u=tree[u].s[0];
        else if(tree[tree[u].s[0]].size+1==k) //当前节点就是待查找结点
            return u;
        else 
            k-=tree[tree[u].s[0]].size+1, u=tree[u].s[1]; //在右侧，计算在右子树的排名
    }
    return -1;
}

inline int build(int l, int r, int pa)
{
    int mid=l+r>>1;
    int u=nodes[tt--];
    tree[u].init(w[mid], pa);
    if(l<mid) tree[u].s[0]=build(l, mid-1, u);
    if(r>mid) tree[u].s[1]=build(mid+1, r, u);
    pushup(u);
    return u;
}

inline void dfs(int u) //将u为根的子树删掉
{
    if(tree[u].s[0]) dfs(tree[u].s[0]);
    if(tree[u].s[1]) dfs(tree[u].s[1]);
    nodes[++tt]=u; //将删除的点放入垃圾回收站
}

signed main()
{
    #ifdef DEBUG
        freopen("./in.txt","r",stdin);
    #else
        ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    #endif

    for(int i=1; i<N; i++) nodes[++tt]=i;
    scanf("%d%d", &n, &m);
    tree[0].ms=-INF; //某点没有孩子，此时孩子指针为0，处理所有没有孩子的情况
    
    //插入删除一段序列时需要查询前驱和后继，在开头和结尾设置两个哨兵防止边界问题
    w[0] = w[n+1] = -INF;
    for(int i=1; i<=n; i++) scanf("%d", &w[i]);
    root=build(0, n+1, 0);

    char op[20];
    while(m--)
    {
        scanf("%s", op);
        if(!strcmp(op, "INSERT"))
        {
            int posi, tot; //插入位置 插入数量
            scanf("%d%d", &posi, &tot);
            posi++; //哨兵
            for(int i=1; i<=tot; i++) scanf("%d", &w[i]);
            int l=get_k(posi), r=get_k(posi+1); 
            splay(l, 0), splay(r, l); //修改树形
            int u=build(1,tot,r);
            tree[r].s[0]=u;
            pushup(r), pushup(l);
        }
        else if(!strcmp(op, "DELETE"))
        {
            int posi, tot; //删除位置 删除数量
            scanf("%d%d", &posi, &tot);
            posi++;
            int l=get_k(posi-1), r=get_k(posi+tot); 
            splay(l, 0), splay(r, l); //修改树形
            dfs(tree[r].s[0]);
            tree[r].s[0]=0;
            pushup(r), pushup(l);
        }
        else if(!strcmp(op, "MAKE-SAME"))
        {
            int posi, tot, c; //op位置 op数量
            scanf("%d%d%d", &posi, &tot, &c);
            posi++;
            int l=get_k(posi-1), r=get_k(posi+tot);  
            splay(l, 0), splay(r, l); //修改树形
            auto &son=tree[tree[r].s[0]]; //找到要修改序列所在子树的根节点
            son.same=1, son.val=c, son.sum=c*tot;
            if(c>0) son.ms=son.ls=son.rs=son.sum;
            else son.ms=c, son.ls=son.rs=0;
            pushup(r), pushup(l);
        }
        else if(!strcmp(op, "REVERSE"))
        {   
            int posi, tot; //反转位置 反转数量
            scanf("%d%d", &posi, &tot);
            posi++;
            int l=get_k(posi-1), r=get_k(posi+tot); 
            splay(l, 0), splay(r, l); //修改树形
            auto &son=tree[tree[r].s[0]]; //找到要修改序列所在子树的根节点

            son.rev^=1;
            swap(son.ls, son.rs); //最大前后缀
            swap(son.s[0], son.s[1]);
            pushup(r), pushup(l);
        }
        else if(!strcmp(op, "GET-SUM"))
        {
            int posi, tot; //求和位置 求和数量
            scanf("%d%d", &posi, &tot);
            posi++;
            int l=get_k(posi-1), r=get_k(posi+tot); 
            splay(l, 0), splay(r, l); //修改树形
            auto &son=tree[tree[r].s[0]]; //找到要修改序列所在子树的根节点
            printf("%d\n", son.sum);
        }
        else //if(!strcmp(op, "MAX-SUM"))
        {
            printf("%d\n", tree[root].ms);
        }

    }
    
    return 0;
}